
/**
  ******************************************************************************
  * Copyright 2021 The grapilot Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       sensor_baro.h
  * @author     baiyang
  * @date       2021-11-21
  ******************************************************************************
  */

#pragma once

#ifdef __cplusplus
extern "C"{
#endif

/*----------------------------------include-----------------------------------*/
#include "sensor_baro_backend.h"

#include <stdint.h>
#include <stdbool.h>

#include <common/gp_config.h>
#include <common/filter/derivative_filter.h>
/*-----------------------------------macro------------------------------------*/
// maximum number of sensor instances
#ifndef BARO_MAX_INSTANCES
#define BARO_MAX_INSTANCES 3
#endif

// maximum number of drivers. Note that a single driver can provide
// multiple sensor instances
#define BARO_MAX_DRIVERS 3

// timeouts for health reporting
#define BARO_TIMEOUT_MS                 500     // timeout in ms since last successful read
#define BARO_DATA_CHANGE_TIMEOUT_MS     2000    // timeout in ms since last successful read that involved temperature of pressure changing
/*----------------------------------typedef-----------------------------------*/
// barometer types
typedef enum {
    BARO_TYPE_AIR,
    BARO_TYPE_WATER
} baro_type_t;

// bitmask values for GND_PROBE_EXT
enum {
    PROBE_BMP085=(1<<0),
    PROBE_BMP280=(1<<1),
    PROBE_MS5611=(1<<2),
    PROBE_MS5607=(1<<3),
    PROBE_MS5637=(1<<4),
    PROBE_FBM320=(1<<5),
    PROBE_DPS280=(1<<6),
    PROBE_LPS25H=(1<<7),
    PROBE_KELLER=(1<<8),
    PROBE_MS5837=(1<<9),
    PROBE_BMP388=(1<<10),
    PROBE_SPL06 =(1<<11),
    PROBE_MSP   =(1<<12),
};

typedef struct {
    // how many drivers do we have?
    uint8_t _num_drivers;

    // backend objects
    sensor_baro_backend *drivers[BARO_MAX_DRIVERS];

    // how many sensors do we have?
    uint8_t _num_sensors;

    // what is the primary sensor at the moment?
    uint8_t _primary;

    uint32_t _log_baro_bit;

    bool init_done;

    struct sensor {
        uint32_t last_update_ms;        // last update time in ms
        uint64_t last_update_us;        // last update time in us
        uint32_t last_change_ms;        // last update time in ms that included a change in reading from previous readings
        float pressure;                 // pressure in Pascal
        float temperature;              // temperature in degrees C
        float altitude;                 // calculated altitude
        float altitude_abs;             // pressure altitude above sea level (m)
        Param_float ground_pressure;
        float p_correction;
        baro_type_t type;               // 0 for air pressure (default), 1 for water pressure
        bool healthy;                   // true if sensor is healthy
        bool alt_ok;                    // true if calculated altitude is ok
        bool calibrated;                // true if calculated calibrated successfully
        Param_int32 bus_id;
    } sensors[BARO_MAX_INSTANCES];

    Param_float                         _alt_offset;
    float                               _alt_offset_active;
    Param_int8                          _primary_baro; // primary chosen by user
    Param_int8                          _ext_bus; // bus number for external barometer
    float                               _last_altitude_EAS2TAS;
    float                               _EAS2TAS;
    float                               _external_temperature;
    uint32_t                            _last_external_temperature_ms;
    DerivativeFilterFloat_Size7         _climb_rate_filter;
    Param_float                         _specific_gravity; // the specific gravity of fluid for an ROV 1.00 for freshwater, 1.024 for salt water
    Param_float                         _user_ground_temperature; // user override of the ground temperature used for EAS2TAS
    float                               _guessed_ground_temperature; // currently ground temperature estimate using our best abailable source

    // when did we last notify the GCS of new pressure reference?
    uint32_t                            _last_notify_ms;

    Param_int8                          _filter_range;  // valid value range from mean value
    Param_int32                         _baro_probe_ext;
} sensor_baro;

/*----------------------------------variable----------------------------------*/

/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
sensor_baro *sensor_baro_get_singleton();
void sensor_baro_ctor();
void sensor_baro_init(void);
void sensor_baro_update(void);

uint8_t sensor_baro_register_sensor(void);
void sensor_baro_set_type(uint8_t instance, baro_type_t type);

// healthy - returns true if sensor and derived altitude are good
bool sensor_baro_healthy();
bool sensor_baro_healthy2(uint8_t instance);

// get current altitude in meters relative to altitude at the time
// of the last calibrate() call
float sensor_baro_get_altitude(void);
float sensor_baro_get_altitude2(uint8_t instance);

// get current altitude in meters above sea level
float sensor_baro_get_altitude_abs(void);
float sensor_baro_get_altitude_abs2(uint8_t instance);

// get last time sample was taken (in ms)
uint32_t sensor_baro_get_last_update(void);
uint32_t sensor_baro_get_last_update2(uint8_t instance);

// get last time sample was taken (in us)
uint64_t sensor_baro_get_last_update_usec(void);
uint64_t sensor_baro_get_last_update2_usec(uint8_t instance);


// pressure in Pascal. Divide by 100 for millibars or hectopascals
float sensor_baro_get_pressure(void);
float sensor_baro_get_pressure2(uint8_t instance);

float sensor_baro_get_external_temperature(void);
float sensor_baro_get_external_temperature2(const uint8_t instance);

// temperature in degrees C
float sensor_baro_get_temperature(void);
float sensor_baro_get_temperature2(uint8_t instance);

float sensor_baro_get_climb_rate(void);

void sensor_baro_calibrate(bool save);
void sensor_baro_update_calibration();

void sensor_baro_assign_param();
void sensor_baro_ground_pressure_set_and_save(uint8_t index, float val);
/*------------------------------------test------------------------------------*/

#ifdef __cplusplus
}
#endif



